#pragma once

#include <mathlib/intype.h>

BEGIN_NAMESPACE_OXGE


/************************************************************************/
//
/************************************************************************/
template<typename T>
class GRAPHIC_TRANSFER Transformation3DT
{
public:
	typedef Transformation3DT<T> TransformType;	
	typedef Vector3T<T> VectorType;
	typedef Point3T<T> PointType;
	typedef Matrix4T<T> MatrixType;	
	typedef Vector4T<T> AffineVectorType;
	typedef std::pair<PointType*, size_t > PointArray;

	virtual MatrixType GetMatrix()const =0;
	virtual PointType operator()(const PointType& pt)const=0;

	PointArray operator()(PointArray& ptArray)const	{
		for(size_t i = 0; i < ptArray.second;++i)		
			ptArray.first[i] = (*this)(ptArray.first[i]);		
		return ptArray;
	}

	

};

/************************************************************************/
//
/************************************************************************/
template<typename T>
class GRAPHIC_TRANSFER MatrixTransform3DT : public Transformation3DT< T >
{
public:
	typedef T ValueType;
	typedef MatrixTransform3DT<T> MatrixTransformType;

	MatrixTransform3DT(){	tranfMat = MatrixType::IDENTITY;	}	

	MatrixTransform3DT(const MatrixType& mat){ tranfMat = mat; }

	MatrixTransformType operator()()const{ return *this; } 
	MatrixTransformType operator()(const TransformType& otherTransf )const{ return MatrixTransformType( GetMatrix() * otherTransf.GetMatrix() );	}

	inline PointType operator()(const PointType& pt)const{	
		AffineVectorType affineVector = pt.GetAffineVector();
		return PointType( tranfMat.RowVector(0).dot(affineVector),
						  tranfMat.RowVector(1).dot(affineVector),
						  tranfMat.RowVector(2).dot(affineVector) );		
	}


	inline MatrixType& GetMatrix(){ return tranfMat; }
	inline MatrixType GetMatrix()const{ return tranfMat; }


protected:
	MatrixType tranfMat;

};



/************************************************************************/
//
/************************************************************************/
template<typename T>
class GRAPHIC_TRANSFER Translation3DT : public Transformation3DT< T>
{
public:	
	typedef T ValueType;
	typedef Translation3DT<T> TranslationType;

	Translation3DT(const VectorType& vec){ transV = vec; } 

	inline TranslationType& Set(const VectorType& offset){ transV = offset ; return *this; }

	PointType operator()(const PointType& pt)const{
		return pt + transV;		
	}	

	typedef MatrixTransform3DT<T> MatrixTransformType;
	MatrixTransformType operator()()const{ return MatrixTransformType(GetMatrix()); } 
	MatrixTransformType operator()(const TransformType& otherTransf )const{ return MatrixTransformType( GetMatrix()*otherTransf.GetMatrix() ); }


protected:
	inline MatrixType GetMatrix()const{
		return MatrixType(  1,0,0,transV.x,
							0,1,0,transV.y,
							0,0,1,transV.z,
							0,0,0,       1  );
	}

protected:
	VectorType transV;

};

/************************************************************************/
//
/************************************************************************/


template<typename T>
class GRAPHIC_TRANSFER Rotation3DT : public Transformation3DT< T >
{
public:
	typedef T ValueType;
	typedef Rotation3DT<T> RotationType;	

	Rotation3DT(T angle, const VectorType& rAxis, const PointType& srcPt = PointType::ZERO ){ 
		axisDir = rAxis, dAngle = angle; axisPoint = srcPt; 
	}

	RotationType& Set(T angle,const VectorType& rAxis, const PointType& srcPt = PointType::ZERO){
		dAngle = angle; axisPoint = srcPt; axisDir = rAxis;
		return *this; 
	}

	RotationType& SetAxisPoint(const PointType& srcPt){	axisPoint = srcPt; return *this; }
	RotationType& SetAxis(const VectorType& vdir){  axisDir = vdir;  return *this; }	
	RotationType& SetAngle(T angle){  dAngle = angle; return *this; }

	typedef MatrixTransform3DT<T> MatrixTransformType;
	MatrixTransformType operator()()const{ return MatrixTransformType(GetMatrix()); } 
	MatrixTransformType operator()(const TransformType& otherTransf )const{ return MatrixTransformType( GetMatrix()*otherTransf.GetMatrix() ); }


public:
	PointType operator()(const PointType& pt)const{
		VectorType v = pt - axisPoint;
		T cosAngle = std::cos(dAngle);
		T sinAngle = std::sin(dAngle);
		VectorType vOffset = v *cosAngle + axisDir*(v.dot(axisDir))*(T(1)-cosAngle) + (axisDir.cross(v))*sinAngle;
		return axisPoint + vOffset;		 
	}


protected:
	MatrixType GetMatrix()const{
		return MatrixType::IDENTITY;
	}

protected:
	PointType axisPoint;
	VectorType axisDir;
	T dAngle;

};


/************************************************************************/
//scale
/************************************************************************/
template<typename T>
class GRAPHIC_TRANSFER Scale3DT : public Transformation3DT< T >
{
public:
	typedef T ValueType;
	typedef Scale3DT<T> ScaleType;


public:
	Scale3DT(const VectorType& vecScale,const PointType& orginPt = PointType::ZERO){
		vScale = vecScale; pOrign = orginPt;
	}

	ScaleType& SetScale(const VectorType& scale){ vScale = scale; return *this; }
	ScaleType& SetOrignPoint(const PointType& orignpt){ pOrign = orignpt; return *this; }

	MatrixType GetMatrix()const{
		return MatrixType::IDENTITY;
	}

public:
	PointType operator()(const PointType& pt)const{
		T dS = vScale.Length();
		VectorType v = vScale.GetNormVector();
		return pt + v * (dS-1) * v.dot(pt - pOrign);
	}	

	typedef MatrixTransform3DT<T> MatrixTransformType;
	MatrixTransformType operator()()const{ return MatrixTransformType(GetMatrix()); } 
	MatrixTransformType operator()(const TransformType& otherTransf )const{ return MatrixTransformType( GetMatrix()*otherTransf.GetMatrix() ); }



protected:
	VectorType vScale;
	PointType pOrign;
};

/************************************************************************/
//mirror
/************************************************************************/
template < typename T>
class GRAPHIC_TRANSFER Reflection3DT : public Transformation3DT< T>
{
public:	
	typedef T ValueType;
	typedef Reflection3DT<T> ReflectionType;

public:
	Reflection3DT(const VectorType& planNorm, const PointType& planPoint){ }

	inline ReflectionType& SetPlane(const VectorType& planNorm, const PointType& planPoint){
		m_planeNorm = planNorm; m_planePoint = planPoint; return *this;
	}
	
	PointType operator()(const PointType& pt)const{
		return pt - m_planeNorm * ( T(2)*(pt - m_planePoint).dot(m_planeNorm) );
	}	

	typedef MatrixTransform3DT<T> MatrixTransformType;
	MatrixTransformType operator()()const{ return MatrixTransformType(GetMatrix()); } 
	MatrixTransformType operator()(const TransformType& otherTransf )const{ return MatrixTransformType( GetMatrix()*otherTransf.GetMatrix() ); }


	MatrixType GetMatrix()const{
		return MatrixType::IDENTITY;
	}

public:
	VectorType m_planeNorm;
	PointType m_planePoint;
};

/************************************************************************/
//shear3d 
/************************************************************************/
template <typename T>
class GRAPHIC_TRANSFER Shear3DT : public Transformation3DT< T>
{
public:
	typedef T ValueType;
	typedef MatrixTransform3DT<T> MatrixTransformType;
	MatrixTransformType operator()()const{ return MatrixTransformType(GetMatrix()); } 
	MatrixTransformType operator()(const TransformType& otherTransf )const{ return MatrixTransformType( GetMatrix()*otherTransf.GetMatrix() ); }
	
	
	MatrixType GetMatrix()const{
		return MatrixType::IDENTITY;
	}

};




/************************************************************************/
//Projection : Ortho Projection
/************************************************************************/
template<typename T> 
class GRAPHIC_TRANSFER OrthoProjectionT : public Transformation3DT< T >
{
public:	
	typedef T ValueType;

	OrthoProjectionT();

	MatrixType GetMatrix()const{
		return MatrixType::IDENTITY;
	}
};



END_NAMESPACE_OXGE
